package org.springframework.beans.factory.annotation;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.beans.factory.support.LookupOverride;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}
 * implementation that autowires annotated fields, setter methods, and arbitrary
 * config methods. Such members to be injected are detected through annotations:
 * by default, Spring's {@link Autowired @Autowired} and {@link Value @Value}
 * annotations.
 *
 * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
 * if available, as a direct alternative to Spring's own {@code @Autowired}.
 *
 * <h3>Autowired Constructors</h3>
 * <p>Only one constructor of any given bean class may declare this annotation with
 * the 'required' attribute set to {@code true}, indicating <i>the</i> constructor
 * to autowire when used as a Spring bean. Furthermore, if the 'required' attribute
 * is set to {@code true}, only a single constructor may be annotated with
 * {@code @Autowired}. If multiple <i>non-required</i> constructors declare the
 * annotation, they will be considered as candidates for autowiring. The constructor
 * with the greatest number of dependencies that can be satisfied by matching beans
 * in the Spring container will be chosen. If none of the candidates can be satisfied,
 * then a primary/default constructor (if present) will be used. If a class only
 * declares a single constructor to begin with, it will always be used, even if not
 * annotated. An annotated constructor does not have to be public.
 *
 * <h3>Autowired Fields</h3>
 * <p>Fields are injected right after construction of a bean, before any
 * config methods are invoked. Such a config field does not have to be public.
 *
 * <h3>Autowired Methods</h3>
 * <p>Config methods may have an arbitrary name and any number of arguments; each of
 * those arguments will be autowired with a matching bean in the Spring container.
 * Bean property setter methods are effectively just a special case of such a
 * general config method. Config methods do not have to be public.
 *
 * <h3>Annotation Config vs. XML Config</h3>
 * <p>A default {@code AutowiredAnnotationBeanPostProcessor} will be registered
 * by the "context:annotation-config" and "context:component-scan" XML tags.
 * Remove or turn off the default annotation configuration there if you intend
 * to specify a custom {@code AutowiredAnnotationBeanPostProcessor} bean definition.
 *
 * <p><b>NOTE:</b> Annotation injection will be performed <i>before</i> XML injection;
 * thus the latter configuration will override the former for properties wired through
 * both approaches.
 *
 * <h3>{@literal @}Lookup Methods</h3>
 * <p>In addition to regular injection points as discussed above, this post-processor
 * also handles Spring's {@link Lookup @Lookup} annotation which identifies lookup
 * methods to be replaced by the container at runtime. This is essentially a type-safe
 * version of {@code getBean(Class, args)} and {@code getBean(String, args)}.
 * See {@link Lookup @Lookup's javadoc} for details.
 * @author Juergen Hoeller
 * @author Mark Fisher
 * @author Stephane Nicoll
 * @author Sebastien Deleuze
 * @author Sam Brannen
 * @see #setAutowiredAnnotationType
 * @see Autowired
 * @see Value
 * @since 2.5
 */
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {

    protected final Log logger = LogFactory.getLog(getClass());

    private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);

    private String requiredParameterName = "required";

    private boolean requiredParameterValue = true;

    private int order = Ordered.LOWEST_PRECEDENCE - 2;

    @Nullable
    private ConfigurableListableBeanFactory beanFactory;

    private final Set<String> lookupMethodsChecked = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

    private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = new ConcurrentHashMap<>(256);

    private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);

    /**
     * Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's
     * standard {@link Autowired @Autowired} annotation.
     * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
     * if available.
     */
    @SuppressWarnings("unchecked")
    public AutowiredAnnotationBeanPostProcessor() {
        this.autowiredAnnotationTypes.add(Autowired.class);
        this.autowiredAnnotationTypes.add(Value.class);
        try{
            this.autowiredAnnotationTypes.add((Class<? extends Annotation>)ClassUtils.forName("javax.inject.Inject",
                    AutowiredAnnotationBeanPostProcessor.class
                    .getClassLoader()));
            logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
        }catch(ClassNotFoundException ex){
            // JSR-330 API not available - simply skip.
        }
    }

    /**
     * Set the 'autowired' annotation type, to be used on constructors, fields,
     * setter methods and arbitrary config methods.
     * <p>The default autowired annotation type is the Spring-provided {@link Autowired}
     * annotation, as well as {@link Value}.
     * <p>This setter property exists so that developers can provide their own
     * (non-Spring-specific) annotation type to indicate that a member is supposed
     * to be autowired.
     */
    public void setAutowiredAnnotationType(Class<? extends Annotation> autowiredAnnotationType) {
        Assert.notNull(autowiredAnnotationType, "'autowiredAnnotationType' must not be null");
        this.autowiredAnnotationTypes.clear();
        this.autowiredAnnotationTypes.add(autowiredAnnotationType);
    }

    /**
     * Set the 'autowired' annotation types, to be used on constructors, fields,
     * setter methods and arbitrary config methods.
     * <p>The default autowired annotation type is the Spring-provided {@link Autowired}
     * annotation, as well as {@link Value}.
     * <p>This setter property exists so that developers can provide their own
     * (non-Spring-specific) annotation types to indicate that a member is supposed
     * to be autowired.
     */
    public void setAutowiredAnnotationTypes(Set<Class<? extends Annotation>> autowiredAnnotationTypes) {
        Assert.notEmpty(autowiredAnnotationTypes, "'autowiredAnnotationTypes' must not be empty");
        this.autowiredAnnotationTypes.clear();
        this.autowiredAnnotationTypes.addAll(autowiredAnnotationTypes);
    }

    /**
     * Set the name of a parameter of the annotation that specifies whether it is required.
     * @see #setRequiredParameterValue(boolean)
     */
    public void setRequiredParameterName(String requiredParameterName) {
        this.requiredParameterName = requiredParameterName;
    }

    /**
     * Set the boolean value that marks a dependency as required
     * <p>For example if using 'required=true' (the default), this value should be
     * {@code true}; but if using 'optional=false', this value should be {@code false}.
     * @see #setRequiredParameterName(String)
     */
    public void setRequiredParameterValue(boolean requiredParameterValue) {
        this.requiredParameterValue = requiredParameterValue;
    }

    public void setOrder(int order) {
        this.order = order;
    }

    @Override
    public int getOrder() {
        return this.order;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        if(!(beanFactory instanceof ConfigurableListableBeanFactory)){
            throw new IllegalArgumentException(
                    "AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: "
                            + beanFactory);
        }
        this.beanFactory = (ConfigurableListableBeanFactory)beanFactory;
    }

    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);
    }

    @Override
    public void resetBeanDefinition(String beanName) {
        this.lookupMethodsChecked.remove(beanName);
        this.injectionMetadataCache.remove(beanName);
    }

    @Override
    @Nullable
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeanCreationException {

        // Let's check for lookup methods here...
        if(!this.lookupMethodsChecked.contains(beanName)){
            if(AnnotationUtils.isCandidateClass(beanClass, Lookup.class)){
                try{
                    Class<?> targetClass = beanClass;
                    do{
                        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                            Lookup lookup = method.getAnnotation(Lookup.class);
                            if(lookup != null){
                                Assert.state(this.beanFactory != null, "No BeanFactory available");
                                LookupOverride override = new LookupOverride(method, lookup.value());
                                try{
                                    RootBeanDefinition mbd =
                                            (RootBeanDefinition)this.beanFactory.getMergedBeanDefinition(beanName);
                                    mbd.getMethodOverrides().addOverride(override);
                                }catch(NoSuchBeanDefinitionException ex){
                                    throw new BeanCreationException(beanName, "Cannot apply @Lookup to beans without "
                                            + "corresponding bean definition");
                                }
                            }
                        });
                        targetClass = targetClass.getSuperclass();
                    }while(targetClass != null && targetClass != Object.class);

                }catch(IllegalStateException ex){
                    throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
                }
            }
            this.lookupMethodsChecked.add(beanName);
        }

        // Quick check on the concurrent map first, with minimal locking.
        Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
        if(candidateConstructors == null){
            // Fully synchronized resolution now...
            synchronized(this.candidateConstructorsCache){
                candidateConstructors = this.candidateConstructorsCache.get(beanClass);
                if(candidateConstructors == null){
                    Constructor<?>[] rawCandidates;
                    try{
                        rawCandidates = beanClass.getDeclaredConstructors();
                    }catch(Throwable ex){
                        throw new BeanCreationException(beanName, "Resolution of declared constructors on bean Class ["
                                + beanClass.getName()
                                + "] from ClassLoader ["
                                + beanClass.getClassLoader()
                                + "] failed", ex);
                    }
                    List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                    Constructor<?> requiredConstructor = null;
                    Constructor<?> defaultConstructor = null;
                    Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
                    int nonSyntheticConstructors = 0;
                    for(Constructor<?> candidate: rawCandidates){
                        if(!candidate.isSynthetic()){
                            nonSyntheticConstructors++;
                        }else if(primaryConstructor != null){
                            continue;
                        }
                        MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
                        if(ann == null){
                            Class<?> userClass = ClassUtils.getUserClass(beanClass);
                            if(userClass != beanClass){
                                try{
                                    Constructor<?> superCtor =
                                            userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                    ann = findAutowiredAnnotation(superCtor);
                                }catch(NoSuchMethodException ex){
                                    // Simply proceed, no equivalent superclass constructor found...
                                }
                            }
                        }
                        if(ann != null){
                            if(requiredConstructor != null){
                                throw new BeanCreationException(beanName, "Invalid autowire-marked constructor: "
                                        + candidate
                                        + ". Found constructor with 'required' Autowired annotation already: "
                                        + requiredConstructor);
                            }
                            boolean required = determineRequiredStatus(ann);
                            if(required){
                                if(!candidates.isEmpty()){
                                    throw new BeanCreationException(beanName, "Invalid autowire-marked constructors: "
                                            + candidates
                                            + ". Found constructor with 'required' Autowired annotation: "
                                            + candidate);
                                }
                                requiredConstructor = candidate;
                            }
                            candidates.add(candidate);
                        }else if(candidate.getParameterCount() == 0){
                            defaultConstructor = candidate;
                        }
                    }
                    if(!candidates.isEmpty()){
                        // Add default constructor to list of optional constructors, as fallback.
                        if(requiredConstructor == null){
                            if(defaultConstructor != null){
                                candidates.add(defaultConstructor);
                            }else if(candidates.size() == 1 && logger.isInfoEnabled()){
                                logger.info("Inconsistent constructor declaration on bean with name '"
                                        + beanName
                                        + "': single autowire-marked constructor flagged as optional - "
                                        + "this constructor is effectively required since there is no "
                                        + "default constructor to fall back to: "
                                        + candidates.get(0));
                            }
                        }
                        candidateConstructors = candidates.toArray(new Constructor<?>[0]);
                    }else if(rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0){
                        candidateConstructors = new Constructor<?>[]{rawCandidates[0]};
                    }else if(nonSyntheticConstructors == 2
                            && primaryConstructor != null
                            && defaultConstructor != null
                            && !primaryConstructor.equals(defaultConstructor)){
                        candidateConstructors = new Constructor<?>[]{primaryConstructor, defaultConstructor};
                    }else if(nonSyntheticConstructors == 1 && primaryConstructor != null){
                        candidateConstructors = new Constructor<?>[]{primaryConstructor};
                    }else{
                        candidateConstructors = new Constructor<?>[0];
                    }
                    this.candidateConstructorsCache.put(beanClass, candidateConstructors);
                }
            }
        }
        return (candidateConstructors.length > 0?candidateConstructors:null);
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        //获取指定类中@Autowired相关注解的元信息
        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try{
            //对Bean的属性进行自动注入
            metadata.inject(bean, beanName, pvs);
        }catch(BeanCreationException ex){
            throw ex;
        }catch(Throwable ex){
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
        }
        return pvs;
    }

    @Deprecated
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
                                                    String beanName) {

        return postProcessProperties(pvs, bean, beanName);
    }

    /**
     * 'Native' processing method for direct calls with an arbitrary target instance,
     * resolving all of its fields and methods which are annotated with {@code @Autowired}.
     * @param bean the target instance to process
     * @throws BeanCreationException if autowiring failed
     */
    public void processInjection(Object bean) throws BeanCreationException {
        Class<?> clazz = bean.getClass();
        InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);
        try{
            metadata.inject(bean, null, null);
        }catch(BeanCreationException ex){
            throw ex;
        }catch(Throwable ex){
            throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
        }
    }

    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
        // Fall back to class name as cache key, for backwards compatibility with custom callers.
        String cacheKey = (StringUtils.hasLength(beanName)?beanName:clazz.getName());
        // Quick check on the concurrent map first, with minimal locking.
        //从容器中查找是否有给定类的autowire相关注解元信息
        InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        if(InjectionMetadata.needsRefresh(metadata, clazz)){
            synchronized(this.injectionMetadataCache){
                metadata = this.injectionMetadataCache.get(cacheKey);
                if(InjectionMetadata.needsRefresh(metadata, clazz)){
                    if(metadata != null){
                        metadata.clear(pvs);
                    }
                    metadata = buildAutowiringMetadata(clazz);
                    //将得到的给定类autowire相关注解元信息存储在容器缓存中
                    this.injectionMetadataCache.put(cacheKey, metadata);
                }
            }
        }
        return metadata;
    }

    //解析给定类@Autowired相关注解元信息
    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        if(!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)){
            return InjectionMetadata.EMPTY;
        }

        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;
        //递归遍历当前类及其所有基类，解析全部注解元信息
        do{
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
            //收集被@Autowired或者@Value标记的Field
            //利用反射机制获取给定类中所有的声明字段，获取字段上的注解信息
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                MergedAnnotation<?> ann = findAutowiredAnnotation(field);
                if(ann != null){
                    if(Modifier.isStatic(field.getModifiers())){
                        if(logger.isInfoEnabled()){
                            logger.info("Autowired annotation is not supported on static fields: " + field);
                        }
                        return;
                    }
                    boolean required = determineRequiredStatus(ann);
                    //将当前字段元信息封装，添加在返回的集合中
                    currElements.add(new AutowiredFieldElement(field, required));
                }
            });
            //收集被@Autowired或者@Value标记的Method
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                if(!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)){
                    return;
                }
                //获取给定方法上的所有注解
                MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
                if(ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))){
                    //不支持静态的方法
                    if(Modifier.isStatic(method.getModifiers())){
                        if(logger.isInfoEnabled()){
                            logger.info("Autowired annotation is not supported on static methods: " + method);
                        }
                        return;
                    }
                    if(method.getParameterCount() == 0){
                        if(logger.isInfoEnabled()){
                            logger.info("Autowired annotation should only be used on methods with parameters: "
                                    + method);
                        }
                    }
                    boolean required = determineRequiredStatus(ann);
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new AutowiredMethodElement(method, required, pd));
                }
            });

            elements.addAll(0, currElements);
            targetClass = targetClass.getSuperclass();
        }while(targetClass != null && targetClass != Object.class);

        return InjectionMetadata.forElements(elements, clazz);
    }

    @Nullable
    private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
        MergedAnnotations annotations = MergedAnnotations.from(ao);
        for(Class<? extends Annotation> type: this.autowiredAnnotationTypes){
            MergedAnnotation<?> annotation = annotations.get(type);
            if(annotation.isPresent()){
                return annotation;
            }
        }
        return null;
    }

    /**
     * Determine if the annotated field or method requires its dependency.
     * <p>A 'required' dependency means that autowiring should fail when no beans
     * are found. Otherwise, the autowiring process will simply bypass the field
     * or method when no beans are found.
     * @param ann the Autowired annotation
     * @return whether the annotation indicates that a dependency is required
     */
    @SuppressWarnings({"deprecation", "cast"})
    protected boolean determineRequiredStatus(MergedAnnotation<?> ann) {
        // The following (AnnotationAttributes) cast is required on JDK 9+.
        return determineRequiredStatus((AnnotationAttributes)ann.asMap(mergedAnnotation -> new AnnotationAttributes(mergedAnnotation
                .getType())));
    }

    /**
     * Determine if the annotated field or method requires its dependency.
     * <p>A 'required' dependency means that autowiring should fail when no beans
     * are found. Otherwise, the autowiring process will simply bypass the field
     * or method when no beans are found.
     * @param ann the Autowired annotation
     * @return whether the annotation indicates that a dependency is required
     * @deprecated since 5.2, in favor of {@link #determineRequiredStatus(MergedAnnotation)}
     */
    @Deprecated
    protected boolean determineRequiredStatus(AnnotationAttributes ann) {
        return (!ann.containsKey(this.requiredParameterName)
                || this.requiredParameterValue == ann.getBoolean(this.requiredParameterName));
    }

    /**
     * Obtain all beans of the given type as autowire candidates.
     * @param type the type of the bean
     * @return the target beans, or an empty Collection if no bean of this type is found
     * @throws BeansException if bean retrieval failed
     */
    protected <T> Map<String, T> findAutowireCandidates(Class<T> type) throws BeansException {
        if(this.beanFactory == null){
            throw new IllegalStateException("No BeanFactory configured - "
                    + "override the getBeanOfType method or specify the 'beanFactory' property");
        }
        return BeanFactoryUtils.beansOfTypeIncludingAncestors(this.beanFactory, type);
    }

    /**
     * Register the specified bean as dependent on the autowired beans.
     */
    private void registerDependentBeans(@Nullable String beanName, Set<String> autowiredBeanNames) {
        if(beanName != null){
            for(String autowiredBeanName: autowiredBeanNames){
                if(this.beanFactory != null && this.beanFactory.containsBean(autowiredBeanName)){
                    this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
                }
                if(logger.isTraceEnabled()){
                    logger.trace("Autowiring by type from bean name '"
                            + beanName
                            + "' to bean named '"
                            + autowiredBeanName
                            + "'");
                }
            }
        }
    }

    /**
     * Resolve the specified cached method argument or field value.
     */
    @Nullable
    private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
        if(cachedArgument instanceof DependencyDescriptor){
            DependencyDescriptor descriptor = (DependencyDescriptor)cachedArgument;
            Assert.state(this.beanFactory != null, "No BeanFactory available");
            return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
        }else{
            return cachedArgument;
        }
    }

    /**
     * Class representing injection information about an annotated field.
     */
    private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {

        private final boolean required;

        private volatile boolean cached = false;

        @Nullable
        private volatile Object cachedFieldValue;

        public AutowiredFieldElement(Field field, boolean required) {
            super(field, null);
            this.required = required;
        }

        @Override
        protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
            //获取要注入的成员变量
            Field field = (Field)this.member;
            Object value;
            //如果成员变量的值先前缓存过
            if(this.cached){
                //从缓存中获取成员变量的值
                value = resolvedCachedArgument(beanName, this.cachedFieldValue);
            }
            //没有缓存
            else{
                //创建一个成员变量的依赖描述符实例
                DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
                desc.setContainingClass(bean.getClass());
                Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
                Assert.state(beanFactory != null, "No BeanFactory available");
                //获取容器的类型转换器
                TypeConverter typeConverter = beanFactory.getTypeConverter();
                try{
                    // 获取注入的值
                    value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
                }catch(BeansException ex){
                    throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
                }
                synchronized(this){
                    //如果成员变量的值没有缓存
                    if(!this.cached){
                        //成员变量的值不为null，并且required属性为true
                        if(value != null || this.required){
                            this.cachedFieldValue = desc;
                            //为指定Bean注册依赖Bean
                            registerDependentBeans(beanName, autowiredBeanNames);
                            if(autowiredBeanNames.size() == 1){
                                String autowiredBeanName = autowiredBeanNames.iterator().next();
                                //如果容器中有指定名称的Bean对象
                                if(beanFactory.containsBean(autowiredBeanName) &&
                                        //依赖对象类型和字段类型匹配，默认按类型注入
                                        beanFactory.isTypeMatch(autowiredBeanName, field.getType())){
                                    //创建一个依赖对象的引用，同时缓存
                                    this.cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName,
                                            field
                                            .getType());
                                }
                            }
                        }
                        //如果获取的依赖关系为null，且获取required属性为false
                        else{
                            //将对应成员变量的值值的缓存设置为null
                            this.cachedFieldValue = null;
                        }
                        //容器已经对当前成员变量的值进行缓存
                        this.cached = true;
                    }
                }
            }
            //如果字段值不为null
            if(value != null){
                //使用反射机制来赋值
                ReflectionUtils.makeAccessible(field);
                field.set(bean, value);
            }
        }

    }

    /**
     * Class representing injection information about an annotated method.
     */
    private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {

        private final boolean required;

        private volatile boolean cached = false;

        @Nullable
        private volatile Object[] cachedMethodArguments;

        public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) {
            super(method, pd);
            this.required = required;
        }

        @Override
        protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
            if(checkPropertySkipping(pvs)){
                return;
            }
            Method method = (Method)this.member;
            Object[] arguments;
            if(this.cached){
                // Shortcut for avoiding synchronization...
                arguments = resolveCachedArguments(beanName);
            }else{
                Class<?>[] paramTypes = method.getParameterTypes();
                arguments = new Object[paramTypes.length];
                DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
                Set<String> autowiredBeans = new LinkedHashSet<>(paramTypes.length);
                Assert.state(beanFactory != null, "No BeanFactory available");
                TypeConverter typeConverter = beanFactory.getTypeConverter();
                for(int i = 0; i < arguments.length; i++){
                    MethodParameter methodParam = new MethodParameter(method, i);
                    DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
                    currDesc.setContainingClass(bean.getClass());
                    descriptors[i] = currDesc;
                    try{
                        Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
                        if(arg == null && !this.required){
                            arguments = null;
                            break;
                        }
                        arguments[i] = arg;
                    }catch(BeansException ex){
                        throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
                    }
                }
                synchronized(this){
                    if(!this.cached){
                        if(arguments != null){
                            DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
                            registerDependentBeans(beanName, autowiredBeans);
                            if(autowiredBeans.size() == paramTypes.length){
                                Iterator<String> it = autowiredBeans.iterator();
                                for(int i = 0; i < paramTypes.length; i++){
                                    String autowiredBeanName = it.next();
                                    if(beanFactory.containsBean(autowiredBeanName)
                                            && beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])){
                                        cachedMethodArguments[i] = new ShortcutDependencyDescriptor(descriptors[i],
                                                autowiredBeanName, paramTypes[i]);
                                    }
                                }
                            }
                            this.cachedMethodArguments = cachedMethodArguments;
                        }else{
                            this.cachedMethodArguments = null;
                        }
                        this.cached = true;
                    }
                }
            }
            if(arguments != null){
                try{
                    ReflectionUtils.makeAccessible(method);
                    method.invoke(bean, arguments);
                }catch(InvocationTargetException ex){
                    throw ex.getTargetException();
                }
            }
        }

        @Nullable
        private Object[] resolveCachedArguments(@Nullable String beanName) {
            Object[] cachedMethodArguments = this.cachedMethodArguments;
            if(cachedMethodArguments == null){
                return null;
            }
            Object[] arguments = new Object[cachedMethodArguments.length];
            for(int i = 0; i < arguments.length; i++){
                arguments[i] = resolvedCachedArgument(beanName, cachedMethodArguments[i]);
            }
            return arguments;
        }

    }

    /**
     * DependencyDescriptor variant with a pre-resolved target bean name.
     */
    @SuppressWarnings("serial")
    private static class ShortcutDependencyDescriptor extends DependencyDescriptor {

        private final String shortcut;

        private final Class<?> requiredType;

        public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {
            super(original);
            this.shortcut = shortcut;
            this.requiredType = requiredType;
        }

        @Override
        public Object resolveShortcut(BeanFactory beanFactory) {
            return beanFactory.getBean(this.shortcut, this.requiredType);
        }

    }

}
